package com.jifen.user.service;

import com.jifen.agent.dao.SmarketJifenDetailDao;
import com.jifen.agent.entity.SmarketJifenDetail;
import com.jifen.common.MyException;
import com.jifen.constant.CommonConstant;
import com.jifen.constant.ErrorCode;
import com.jifen.mch.dao.MchDao;
import com.jifen.mch.dao.MchJifenDetailDao;
import com.jifen.mch.entity.Mch;
import com.jifen.mch.entity.MchJifenDetail;
import com.jifen.mch.vo.MchInfoVo;
import com.jifen.mch.vo.MchParam;
import com.jifen.mch.vo.QrCodeVo;
import com.jifen.user.dao.UserDao;
import com.jifen.user.dao.UserInviteProfitDao;
import com.jifen.user.dao.UserJifenDetailDao;
import com.jifen.user.dao.UserPayDao;
import com.jifen.user.entity.User;
import com.jifen.user.entity.UserJifenDetail;
import com.jifen.user.entity.UserPay;
import com.jifen.user.vo.*;
import com.jifen.utils.DateUtils;
import com.jifen.utils.DigestsUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {

    @Autowired
    UserDao userDao;
    @Autowired
    MchDao mchDao;
    @Autowired
    UserPayDao userPayDao;
    @Autowired
    UserJifenDetailDao userJifenDetailDao;
    @Autowired
    MchJifenDetailDao mchJifenDetailDao;
    @Autowired
    SmarketJifenDetailDao smarketJifenDetailDao;
    @Autowired
    UserInviteProfitDao userInviteProfitDao;
    @Resource
    RedisTemplate<String, Object> redisTemplate;

    /**
     * 注册
     * @param param
     */
    public void register(UserParam param){
        // 短信验证码
        String sysSmsAuthcode = (String) redisTemplate.opsForValue().get("sms_authcode_" + param.getMobile());
        if (sysSmsAuthcode == null || !sysSmsAuthcode.equals( param.getSmsAuthcode())) {
            throw new MyException(ErrorCode.SMS_AUTHCODE_ERR);
        }
        // 手机号是否存在
        User user = userDao.getByMobile( param.getMobile());
        if (user != null) {
            throw new MyException(ErrorCode.MOBILE_ALREADY_REG);
        }
        user = new User();
        user.setMobile(param.getMobile());
        user.setPassword(DigestsUtils.md5( param.getPassword().toLowerCase() + CommonConstant.SALT));
        user.setDeviceType(param.getDeviceType());
        user.setCreateTime(DateUtils.getDate());
        if(StringUtils.isNotBlank(param.getInviterMobile())){
            User inviter = userDao.getByMobile(param.getInviterMobile());
            if(inviter!=null){
                user.setInviter(inviter.getId());
            }
        }
        userDao.insertSelective(user);
        redisTemplate.delete("sms_authcode_" + param.getMobile());
    }

    /**
     * 登录
     * @param mobile
     * @param password
     */
    public Map<String, Object> login(String mobile, String password){
        // 手机号是否存在
        User user = userDao.getByMobile(mobile);
        if (user == null) {
            throw new MyException(ErrorCode.MOBILE_NOT_REG);
        }
        // 密码是否正确
        if (!user.getPassword().equals(DigestsUtils.md5(password.toLowerCase() + CommonConstant.SALT))) {
            throw new MyException(ErrorCode.LOGIN_PASSWORD_FAIL);
        }
        String token = DigestsUtils.md5(mobile + "&token&" + DateUtils.getDate().getTime());
        TokenUserVo tokenUser = new TokenUserVo();
        tokenUser.setId(user.getId());
        tokenUser.setMobile(user.getMobile());
        tokenUser.setPassword(DigestsUtils.md5(password.toLowerCase() + CommonConstant.SALT));
        if(user.getIsMch()==1){
            // 商家
            Mch mch = mchDao.getByUid(user.getId());
            tokenUser.setMchId(mch!=null?mch.getId():0);
        }
        // 删除以前的token
        String oldToken = (String) redisTemplate.opsForValue().get(mobile);
        if(oldToken!=null){
            redisTemplate.delete(oldToken);
        }
        redisTemplate.opsForValue().set(token, tokenUser, 30, TimeUnit.DAYS);
        redisTemplate.opsForValue().set(mobile, token, 30, TimeUnit.DAYS);
        Integer sid = 0;
        if(user.getIsAdmin()==1){
            sid = mchDao.getIdByMuid(user.getId());
        }
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("sid", sid);
        return map;
    }

    /**
     * 注销
     * @param token
     */
    public void logout(String token){
        TokenUserVo tokenUser = getTokenPuser(token);
        if(tokenUser!=null) {
            redisTemplate.delete(token);
        }
    }

    /**
     * 找回密码
     * @param mobile
     * @param token
     * @param smsAuthcode
     * @param newPassword
     */
    public void forgetPassword(String mobile, String token, String smsAuthcode, String newPassword) {
        int uid = 0;
        if(StringUtils.isBlank(token)) {
            // 验证短信验证码
            String serverSmsAuthcode = (String) redisTemplate.opsForValue().get("sms_authcode_" + mobile);
            if (serverSmsAuthcode == null || !serverSmsAuthcode.equals(smsAuthcode)) {
                throw new MyException(ErrorCode.SMS_AUTHCODE_ERR);
            }
            // 根据手机号查询用户
            User user = userDao.getByMobile(mobile);
            uid = user.getId();
        }else{
            TokenUserVo tokenUserVo = getTokenUser(token);
            uid = tokenUserVo.getId();
        }
        // 修改密码
        newPassword = DigestsUtils.md5(newPassword.toLowerCase() + CommonConstant.SALT);
        User updateUser = new User();
        updateUser.setId(uid);
        updateUser.setPassword(newPassword);
        userDao.updateByPrimaryKeySelective(updateUser);
    }

    /**
     * 修改密码
     * @param token
     * @param oldPassword
     * @param newPassword
     */
    public void modifyPassword(String token, String oldPassword, String newPassword) {
        TokenUserVo tokenUserVo = getTokenUser(token);
        // 验证旧密码
        String password = tokenUserVo.getPassword();
        String hashPassword = DigestsUtils.md5(oldPassword.toLowerCase() + CommonConstant.SALT);
        if (!password.equals(hashPassword)) {
            throw new MyException(ErrorCode.OLD_PASSWORD_FAIL);
        }
        // 修改密码
        newPassword = DigestsUtils.md5(newPassword.toLowerCase() + CommonConstant.SALT);
        User updateUser = new User();
        updateUser.setId(tokenUserVo.getId());
        updateUser.setPassword(newPassword);
        userDao.updateByPrimaryKeySelective(updateUser);
        // 更新缓存
        tokenUserVo.setPassword(newPassword);
        redisTemplate.opsForValue().set(token, tokenUserVo, 7, TimeUnit.DAYS);
    }

    /**
     * 校验会话有效性
     * @param token
     * @return
     */
    public TokenUserVo getTokenUser(String token) {
        if(StringUtils.isNotBlank(token)) {
            TokenUserVo user = (TokenUserVo) redisTemplate.opsForValue().get(token);
            if (user == null) {
                throw new MyException(ErrorCode.NOT_LOGIN);
            } else {
                return user;
            }
        }else{
            throw new MyException(ErrorCode.NOT_LOGIN);
        }
    }

    /**
     * 从缓存获取用户信息
     * @param token
     * @return
     */
    public TokenUserVo getTokenPuser(String token) {
        if(StringUtils.isNotBlank(token)) {
            TokenUserVo user = (TokenUserVo) redisTemplate.opsForValue().get(token);
            return user;
        }else {
            return null;
        }
    }

    /**
     * 用户信息
     * @param token
     * @return
     */
    public UserVo getUserInfo(String token){
        TokenUserVo tokenUser = getTokenUser(token);
        User user = userDao.selectByPrimaryKey(tokenUser.getId());
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        if(user.getInviter()!=null) {
            User inviter = userDao.selectByPrimaryKey(user.getInviter());
            if (inviter != null) {
                userVo.setInviterMobile(inviter.getMobile());
            }
        }
        Integer sid = 0;
        if(user.getIsAdmin()==1){
            sid = mchDao.getIdByMuid(user.getId());
            userVo.setSid(sid);
        }
        userVo.setRecommendMchFlag(mchDao.getInviteNum(tokenUser.getId())>1?1:0);
        return userVo;
    }

    /**
     * 商家信息
     * @param token
     * @return
     */
    public MchVo getMchInfo(String token){
        TokenUserVo tokenUser = getTokenUser(token);
        Mch mch = mchDao.getByUid(tokenUser.getId());
        MchVo mchVo = new MchVo();
        if(mch!=null){
            mchVo.setId(mch.getId());
            mchVo.setJifen(mch.getJifen());
            mchVo.setJifenGiveRatio(mch.getJifenGiveRatio());
            mchVo.setAddress(mch.getAddress());
            mchVo.setHead(mch.getHead());
            mchVo.setPhone(mch.getPhone());
            mchVo.setIntroduce(mch.getIntroduce());
        }
        return mchVo;
    }

    /**
     * 代理信息
     * @param token
     * @return
     */
    public AgentVo getAgentInfo(String token){
        TokenUserVo tokenUser = getTokenUser(token);
        User user = userDao.selectByPrimaryKey(tokenUser.getId());
        AgentVo agentVo = new AgentVo();
        return agentVo;
    }

    /**
     * 扫描二维码
     * @param token
     * @param content
     * @return
     */
    public Map<String, Object> scanQrCode(String token, String content){
        TokenUserVo tokenUser = getTokenUser(token);
        Map<String, Object> map = new HashMap<>();
        QrCodeVo qrCodeVo = (QrCodeVo)redisTemplate.opsForValue().get(content);
        if(qrCodeVo==null){
            throw new MyException(ErrorCode.QRCODE_FAIL);
        }
        map.put("mchName", qrCodeVo.getMchName());
        map.put("consumeAmount", qrCodeVo.getConsumeAmount());
        if(qrCodeVo.getType()==1) {
            // 商家
            map.put("jifen", qrCodeVo.getJifen());
        }else{
            // 超市
            User account = userDao.getAccount(tokenUser.getId());
            map.put("jifen", account.getJifen());
            map.put("deductMoney", qrCodeVo.getDeductMoney());
            map.put("deductBalance", account.getDeductMoney());
            map.put("payMoney", qrCodeVo.getPayMoney());
        }
        map.put("time", DateUtils.formatDate("yyyy-MM-dd HH:mm:ss"));
        map.put("type", qrCodeVo.getType());
        return map;
    }

    /**
     * 积分交易
     * @param token
     * @param content
     */
    @Transactional
    public void confirmTrade(String token, String content){
        TokenUserVo tokenUser = getTokenUser(token);
        QrCodeVo qrCodeVo = (QrCodeVo)redisTemplate.opsForValue().get(content);
        if(qrCodeVo!=null){
            if (qrCodeVo.getType() == 1) {//商家领取积分
                if (mchDao.getJifen(qrCodeVo.getMchId()) < qrCodeVo.getJifen()) {
                    throw new MyException(ErrorCode.MCH_JIFEN_BUZU);
                }
                // 用户增加积分
                UserParam userParam = new UserParam();
                userParam.setId(tokenUser.getId());
                userParam.setJifen(qrCodeVo.getJifen());
                userDao.updateJifen(userParam);
                // 用户积分明细
                UserJifenDetail userJifenDetail = new UserJifenDetail();
                userJifenDetail.setUid(tokenUser.getId());
                userJifenDetail.setType(1);
                userJifenDetail.setJifen(qrCodeVo.getJifen());
                userJifenDetail.setRemark(qrCodeVo.getMchName());
                userJifenDetail.setCreateTime(DateUtils.getDate());
                userJifenDetailDao.insertSelective(userJifenDetail);
                // 商户减少积分
                MchParam mchParam = new MchParam();
                mchParam.setId(qrCodeVo.getMchId());
                mchParam.setJifen(qrCodeVo.getJifen());
                mchParam.setJifenType(1);
                mchDao.updateJifen(mchParam);
                // 商户积分明细
                MchJifenDetail mchJifenDetail = new MchJifenDetail();
                mchJifenDetail.setMchId(qrCodeVo.getMchId());
                mchJifenDetail.setType(2);
                mchJifenDetail.setJifen(qrCodeVo.getJifen());
                mchJifenDetail.setAmount(qrCodeVo.getConsumeAmount());
                mchJifenDetail.setRemark(tokenUser.getMobile() + "消费 " + qrCodeVo.getConsumeAmount() + "元");
                mchJifenDetail.setCreateTime(DateUtils.getDate());
                mchJifenDetailDao.insertSelective(mchJifenDetail);
            } else if (qrCodeVo.getType() == 2) {//超市消费积分
                User user = userDao.selectByPrimaryKey(tokenUser.getId());
                if (user.getJifen() < qrCodeVo.getJifen()) {
                    throw new MyException(ErrorCode.JIFEN_BUZU);
                }
                // 用户减少积分
                UserParam userParam = new UserParam();
                userParam.setId(tokenUser.getId());
                userParam.setJifen(qrCodeVo.getJifen());
                userParam.setJifenType(1);
                userDao.updateJifen(userParam);
                // 用户积分明细
                UserJifenDetail userJifenDetail = new UserJifenDetail();
                userJifenDetail.setUid(tokenUser.getId());
                userJifenDetail.setType(2);
                userJifenDetail.setJifen(qrCodeVo.getJifen());
                userJifenDetail.setRemark(qrCodeVo.getMchName());
                userJifenDetail.setCreateTime(DateUtils.getDate());
                userJifenDetailDao.insertSelective(userJifenDetail);
                // 超市增加积分
                MchParam mchParam = new MchParam();
                mchParam.setId(qrCodeVo.getMchId());
                mchParam.setJifen(qrCodeVo.getJifen());
                mchParam.setJifenType(1);
                mchDao.updateJifen(mchParam);
                // 超市积分明细
                SmarketJifenDetail smarketJifenDetail = new SmarketJifenDetail();
                smarketJifenDetail.setSid(qrCodeVo.getMchId());
                smarketJifenDetail.setGuid(mchDao.getAgentId(qrCodeVo.getMchId()));
                smarketJifenDetail.setType(1);
                smarketJifenDetail.setJifen(qrCodeVo.getJifen());
                smarketJifenDetail.setRemark(tokenUser.getMobile() + "消费");
                smarketJifenDetail.setCreateTime(DateUtils.getDate());
                smarketJifenDetailDao.insertSelective(smarketJifenDetail);
            }
            redisTemplate.delete(content);
        }else{
            throw new MyException(ErrorCode.QRCODE_INVALID);
        }
    }

    /**
     * 超市现金消费
     * @param tradeNo
     * @param outTradeNo
     * @param qrcodeContent
     * @param deductMoney
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void smarketTrade(String tradeNo, String outTradeNo, String qrcodeContent, double deductMoney, String mobile){
        QrCodeVo qrCodeVo = (QrCodeVo)redisTemplate.opsForValue().get(qrcodeContent);
        UserPay pay = userPayDao.getByTradeNo(tradeNo);
        if(pay.getState()==0) {
            // 用户减少抵扣金
            UserParam userParam = new UserParam();
            userParam.setId(pay.getUid());
            userParam.setJifen(deductMoney);
            userDao.reduceDeductMoney(userParam);
            // 超市增加积分
            MchParam mchParam = new MchParam();
            mchParam.setId(qrCodeVo.getMchId());
            mchParam.setJifen(qrCodeVo.getJifen());
            mchParam.setJifenType(1);
            mchDao.updateJifen(mchParam);
            // 超市积分明细
            SmarketJifenDetail smarketJifenDetail = new SmarketJifenDetail();
            smarketJifenDetail.setSid(qrCodeVo.getMchId());
            smarketJifenDetail.setGuid(mchDao.getAgentId(qrCodeVo.getMchId()));
            smarketJifenDetail.setType(1);
            smarketJifenDetail.setJifen(qrCodeVo.getJifen());
            smarketJifenDetail.setRemark(mobile + "消费");
            smarketJifenDetail.setCreateTime(DateUtils.getDate());
            smarketJifenDetailDao.insertSelective(smarketJifenDetail);
            // 更新交易
            UserPay uPay = new UserPay();
            uPay.setId(pay.getId());
            uPay.setState(1);
            uPay.setOutTradeNo(outTradeNo);
            uPay.setUpdateTime(DateUtils.getDate());
            userPayDao.updateByPrimaryKeySelective(uPay);

            redisTemplate.delete(qrcodeContent);
        }
    }

    /**
     * 积分明细
     * @param param
     * @return
     */
    public List<UserJifenDetailVo> getJifenDetail(UserParam param){
        TokenUserVo tokenUser = getTokenUser(param.getToken());
        param.setPageNo((param.getPageNo() - 1) * param.getPageSize());
        param.setId(tokenUser.getId());
        List<UserJifenDetail> detailList = userJifenDetailDao.selectPage(param);
        List<UserJifenDetailVo> voList = new ArrayList<>();
        for (int i = 0; i < detailList.size(); i++) {
            UserJifenDetailVo vo = new UserJifenDetailVo();
            BeanUtils.copyProperties(detailList.get(i), vo);
            vo.setDate(DateUtils.formatDate(detailList.get(i).getCreateTime(),"yyyy.MM.dd"));
            voList.add(vo);
        }
        return voList;
    }

    /**
     * 赠送积分
     * @param token
     * @param receiveMobile
     * @param smsAuthcode
     * @param jifen
     */
    @Transactional
    public void giveJifen(String token, String receiveMobile , String smsAuthcode, int jifen){
        TokenUserVo tokenUser = getTokenUser(token);
        // 短信验证码
        String sysSmsAuthcode = (String) redisTemplate.opsForValue().get("sms_authcode_" + tokenUser.getMobile());
        if (sysSmsAuthcode == null || !sysSmsAuthcode.equals(smsAuthcode)) {
            throw new MyException(ErrorCode.SMS_AUTHCODE_ERR);
        }
        User account = userDao.getAccount(tokenUser.getId());
        if(account.getJifen()<jifen){
            throw new MyException(ErrorCode.JIFEN_BUZU);
        }
        User receiveUser = userDao.getByMobile(receiveMobile);
        if(receiveUser==null){
            throw new MyException(ErrorCode.MOBILE_NOT_REG);
        }
        if(receiveUser.getId().intValue()==tokenUser.getId().intValue()){
            throw new MyException(ErrorCode.GIVE_JIFEN_ZIJI);
        }
        // 赠送方减少积分
        UserParam userReduce= new UserParam();
        userReduce.setId(tokenUser.getId());
        userReduce.setJifen(jifen);
        userReduce.setJifenType(1);
        userDao.updateJifen(userReduce);
        // 接受方增加积分
        UserParam userAdd = new UserParam();
        userAdd.setId(receiveUser.getId());
        userAdd.setJifen(jifen);
        userAdd.setJifenType(0);
        userDao.updateJifen(userAdd);
        // 赠送方积分明细
        UserJifenDetail giveJifenDetail = new UserJifenDetail();
        giveJifenDetail.setUid(tokenUser.getId());
        giveJifenDetail.setType(2);
        giveJifenDetail.setJifen((double)jifen);
        giveJifenDetail.setRemark("积分转赠"+receiveMobile);
        giveJifenDetail.setChannel(2);
        giveJifenDetail.setCreateTime(DateUtils.getDate());
        userJifenDetailDao.insertSelective(giveJifenDetail);
        // 接受方积分明细
        UserJifenDetail receiveJifenDetail = new UserJifenDetail();
        receiveJifenDetail.setUid(receiveUser.getId());
        receiveJifenDetail.setType(1);
        receiveJifenDetail.setJifen((double)jifen);
        receiveJifenDetail.setRemark("积分转赠"+tokenUser.getMobile());
        receiveJifenDetail.setChannel(2);
        receiveJifenDetail.setCreateTime(DateUtils.getDate());
        userJifenDetailDao.insertSelective(receiveJifenDetail);
    }

    /**
     * 添加邀请人
     * @param token
     * @param inviterMobile
     */
    public void addInviter(String token, String inviterMobile){
        TokenUserVo tokenUser = getTokenUser(token);
        User user = userDao.selectByPrimaryKey(tokenUser.getId());
        if(user.getInviter()==null) {
            User inviter = userDao.getByMobile(inviterMobile);
            if (inviter != null) {
                User updateUser = new User();
                updateUser.setId(tokenUser.getId());
                updateUser.setInviter(inviter.getId());
                userDao.updateByPrimaryKeySelective(updateUser);
            }else{
                throw new MyException(ErrorCode.INVITER_NOT_REG);
            }
        }
    }

    /**
     * 修改头像
     * @param token
     * @param user
     */
    public void modifyHead(String token, User user){
        TokenUserVo tokenUser = getTokenUser(token);
        user.setId(tokenUser.getId());
        userDao.updateByPrimaryKeySelective(user);
    }

    /**
     * 邀请收益汇总
     * @param param
     * @return
     */
    public Map<String, Object> getInviteProfit(UserParam param){
        TokenUserVo tokenUser = getTokenUser(param.getToken());
        Double lastMonthProfit = userInviteProfitDao.sumProfit(tokenUser.getId(), DateUtils.getLastMonth(), "month");
        Double curMonthProfit = userInviteProfitDao.sumProfit(tokenUser.getId(), DateUtils.formatDate("yyyy-MM"), "month");
        Double todayProfit = userInviteProfitDao.sumProfit(tokenUser.getId(), DateUtils.formatDate("yyyy-MM-dd"), null);
        Map<String, Object> map = new HashMap<>();
        map.put("lastMonthProfit", lastMonthProfit!=null?lastMonthProfit:0);
        map.put("curMonthProfit", curMonthProfit!=null?curMonthProfit:0);
        map.put("todayProfit", todayProfit!=null?todayProfit:0);
        return map;
    }

    /**
     * 邀请商家收益明细
     * @param param
     * @return
     */
    public List<UserInviteProfitVo> getInviteProfitDetail(UserParam param){
        TokenUserVo tokenUser = getTokenUser(param.getToken());
        param.setPageNo((param.getPageNo() - 1) * param.getPageSize());
        param.setId(tokenUser.getId());
        return userInviteProfitDao.getProfits(param);
    }

    /**
     * 我邀请的商家
     * @param param
     * @return
     */
    public List<MchInfoVo> getInviteMchs(UserParam param){
        TokenUserVo tokenUser = getTokenUser(param.getToken());
        param.setPageNo((param.getPageNo() - 1) * param.getPageSize());
        return mchDao.getByInvite(tokenUser.getId(), param.getPageNo(), param.getPageSize());
    }
}
